package x.ovo.wechat.bot.impl.core;

import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.text.StrUtil;
import x.ovo.wechat.bot.core.Context;
import x.ovo.wechat.bot.core.entity.Contact;
import x.ovo.wechat.bot.core.enums.SyncCheck;
import x.ovo.wechat.bot.core.event.SystemEvent;
import x.ovo.wechat.bot.core.exception.SyncCheckException;
import x.ovo.wechat.bot.core.http.WechatApi;
import x.ovo.wechat.bot.core.http.result.SyncCheckResult;
import x.ovo.wechat.bot.core.http.result.WebSyncResult;
import x.ovo.wechat.bot.impl.config.ClientConfig;

@Slf4j(topic = "SyncChecker")
public class SyncChecker implements Runnable {

    private final Context ctx = Context.INSTANCE;
    private final WechatApi api = ctx.getApi();
    private final ClientConfig config = ClientConfig.get();
    private int counter = 0;

    @Override
    public void run() {
        log.info("心跳检测及消息拉取线程已启动");
        while (this.ctx.isRunning()) {
            SyncCheckResult result = null;
            try {
                result = this.api.syncCheck();
                this.ctx.setLastHeartbeat(System.currentTimeMillis());
                log.debug("sync check ret: {}, seletor: {}", result.getRetCode(), result.getSelector());
                if (!SyncCheck.RetCode.NORMAL.equals(result.getRetCode()))
                    throw new SyncCheckException(StrUtil.format("心跳检测异常：{}", result.getRetCode().getMessage()));
                this.handle(result);
            } catch (SyncCheckException e) {
                // 如果出现同步异常，则重新登录
                log.warn("心跳同步异常: {} - {}", result.getRetCode().getCode(), result.getRetCode().getMessage());
                this.ctx.setLogedin(false);
                this.ctx.setAutoLogedin(false);
                this.api.login(config.getAutoLogin());
                log.info("第 {} 次重试，登录 {}", counter++, this.ctx.isLogedin() ? "成功" : "失败");
                if (counter > this.config.getReteyCount()) {
                    log.error("同步状态出现异常，且重试已达最大次数，进程即将退出");
                    new SystemEvent("同步状态出现异常，且重试已达最大次数，进程即将退出").fire();
                    System.exit(0);
                }
            } catch (Exception e) {
                log.error("同步异常: {}", e.getMessage());
            }
        }
    }

    private void handle(SyncCheckResult checkResult) {
        // 心跳正常，无新消息需要拉取，返回
        if (SyncCheck.Selector.NORMAL.equals(checkResult.getSelector())) return;

        // 拉取新消息
        WebSyncResult syncResult = this.api.webSync();
        // 更新同步key
        if (syncResult.getSyncKey().getCount() > 0) this.ctx.getSession().setSyncKey(syncResult.getSyncKey());
        if (syncResult.getSyncCheckKey().getCount() > 0)
            this.ctx.getSession().setSyncCheckKey(syncResult.getSyncCheckKey());
        // 获取消息列表并处理
        if (syncResult.getAddMsgCount() > 0 && CollUtil.isNotEmpty(syncResult.getAddMsgList())) {
            log.debug("add msg list: {}", syncResult.getAddMsgList());
            MessageConsumer.addAll(syncResult.getAddMsgList());
        }
        if (syncResult.getModContactCount() > 0 && CollUtil.isNotEmpty(syncResult.getModContactList())) {
            log.info("mod contact list: {}", syncResult.getModContactList().stream().map(Contact::getNickName).toList());
            new SystemEvent(StrUtil.format("[contact] mod contact list: {}", syncResult.getModContactList().stream().peek(Contact::format).map(Contact::getNickName).toList())).fire();
        }
        if (syncResult.getDelContactCount() > 0 && CollUtil.isNotEmpty(syncResult.getDelContactList())) {
            log.info("del contact list: {}", syncResult.getDelContactList().stream().map(Contact::getNickName).toList());
            new SystemEvent(StrUtil.format("[contact] del contact list: {}", syncResult.getDelContactList().stream().peek(Contact::format).map(Contact::getNickName).toList())).fire();
        }
        if (syncResult.getModChatRoomMemberCount() > 0 && CollUtil.isNotEmpty(syncResult.getModChatRoomMemberList())) {
            log.info("mod chat room member list: {}", syncResult.getModChatRoomMemberList().stream().peek(Contact::format).map(Contact::getNickName).toList());
            new SystemEvent(StrUtil.format("[contact] mod chat room member list: {}", syncResult.getModChatRoomMemberList().stream().map(Contact::getNickName).toList())).fire();
        }

    }
}
